﻿using wwl.Contract.Dtos.Common;
using wwl.Contract.Dtos.Requests.Rbac;
using wwl.Contract.Interfaces.Common;
using wwl.Domain.Entities.Rbac;

namespace wwl.Contract.Interfaces.Rbac
{
  /// <summary>
  /// 租户聚合根专用仓储接口（DDD 领域仓储模式）
  /// 继承通用仓储接口 <see cref="IGenericRepository{Tenant}"/>，扩展租户专属数据操作契约
  /// 聚焦权限模块（Rbac）中租户聚合根的个性化数据访问需求，封装租户相关领域数据操作规则
  /// </summary>
  /// <remarks>
  /// DDD 设计核心：仓储接口属于契约层，仅定义操作契约，不包含具体实现（实现类位于数据访问层）
  /// 依赖倒置原则体现：领域层依赖此接口，数据访问层实现接口，解耦领域与数据访问技术
  /// </remarks>
  public interface ITenantRepository : IGenericRepository<Tenant>
  {
    /// <summary>
    /// 异步校验租户编码是否已存在（DDD 领域唯一性规则支撑）
    /// </summary>
    /// <param name="tenantCode">待校验的租户编码（领域核心业务标识）</param>
    /// <param name="excludeId">可选参数，需排除的租户ID（更新场景下排除自身，避免自我冲突）</param>
    /// <returns>
    /// 布尔值：true 表示编码已存在（违反租户编码唯一的领域规则），false 表示编码可用
    /// </returns>
    /// <remarks>
    /// 1. 支撑领域核心规则：租户编码是业务层面的唯一标识，此方法为该规则提供数据校验能力，符合 DDD“领域规则通过仓储保障”思想。
    /// 2. 适配两种业务场景：
    ///    - 创建租户：不传 excludeId，校验编码是否被其他租户占用；
    ///    - 更新租户：传入当前租户ID，排除自身后校验编码唯一性。
    /// 3. 契约层定义：仅暴露必要参数与返回值，隐藏数据查询细节（如SQL语句、索引使用），符合仓储模式“隔离数据访问细节”的核心作用。
    /// </remarks>
    Task<bool> ExistsByCodeAsync(string tenantCode, string? excludeId = null);

    /// <summary>
    /// 异步执行租户专属分页查询（DDD 领域个性化查询契约）
    /// </summary>
    /// <param name="request">租户分页查询请求模型（封装租户特有筛选条件与分页参数）</param>
    /// <returns>
    /// 分页结果对象 <see cref="PagedResult{Tenant}"/>，包含符合条件的租户聚合根列表与总条数
    /// </returns>
    /// <remarks>
    /// 1. 与通用分页的区别：通用分页需手动传入筛选表达式，本方法直接接收租户专属请求模型（<see cref="TenantPagedRequest"/>），
    ///    封装租户特有的筛选逻辑（如按租户名称、状态筛选），更贴合领域业务场景，符合 DDD“仓储适配领域需求”原则。
    /// 2. 聚合根查询：返回完整的 Tenant 聚合根，而非零散数据，确保领域层操作的是完整的聚合根对象，符合 DDD“聚合根整体操作”思想。
    /// 3. 数据传输适配：请求模型（Request）与结果模型（PagedResult）均属于契约层，统一数据交互格式，避免领域实体直接暴露给外部。
    /// </remarks>
    Task<PagedResult<Tenant>> GetPagedAsync(TenantPagedRequest request);
  }
}